<template>
    <div class="file-upload mb-3">
        <div class="file-upload-container" @click.prevent="triggerUpload" v-bind="$attrs">
            <slot v-if="fileStatus === 'loading'" name='loading'>
                <button class="btn btn-primary" disabled>正在上传...</button>
            </slot>
            <slot v-else-if="fileStatus === 'success'" name='uploaded' :uploadedData="uploadedData">
                <button class="btn btn-primary">上传成功</button>
            </slot>
            <slot v-else name="default">
                <button class="btn btn-primary">点击上传</button>
            </slot>
        </div>
        <input type="file" class="file-input d-none" @change.prevent="handleFileChange" ref="fileInput" />
    </div>
</template>

<script lang="ts">
// 在 vue3.3 中，可以直接使用 defineOptions 来定义随性
export default {
    inheritAttrs: false
}

</script>

<script setup lang="ts">
import axios from '@/utils/http-utils';
import { PropType, ref, watch } from 'vue';

type UploadStatus = 'ready' | 'loading' | 'success' | 'error';
type CheckFunction = (file: File) => boolean;

const props = defineProps({
    action: {
        type: String,
        required: true,
    },
    beforeUpload: {
        type: Function as PropType<CheckFunction>
    },
    uploaded: {
        type: Object
    }
});

const emit = defineEmits(['file-uploaded', 'file-uploaded-error']);

const fileInput = ref<HTMLInputElement | null>(null);
const fileStatus = ref<UploadStatus>(props.uploaded ? 'success' : 'ready')
const uploadedData = ref(props.uploaded);

watch(() => props.uploaded, (newValue) => {
    if (newValue) {
        fileStatus.value = 'success'
        uploadedData.value = newValue
    }
})

const triggerUpload = () => {
    if (fileInput.value) {
        fileInput.value.click();
    }
}

const handleFileChange = (e: Event) => {
    const currentTarget = e.target as HTMLInputElement;
    if (currentTarget.files) {
        const files = Array.from(currentTarget.files);
        if (props.beforeUpload) {
            const result = props.beforeUpload(files[0]);
            if (!result) {
                return;
            }
        }
        fileStatus.value = 'loading';
        const formData = new FormData();
        formData.append('file', files[0]);
        axios.post(props.action, formData, {
            headers: {
                'Content-Type': 'multipart/form-data'
            }
        }).then((resp) => {
            fileStatus.value = 'success';
            uploadedData.value = resp.data;
            emit('file-uploaded', resp.data);
            // console.log(resp.data);
        }).catch((err) => {
            fileStatus.value = 'error';
            emit('file-uploaded-error', err);
        }).finally(() => {
            if (fileInput.value) {
                fileInput.value.value = '';
            }
        })
    }
}

</script>

<style></style>